
package com.marianhello.bgloc;

import java.util.Iterator;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.util.Log;


public class LcmmLocationProvider extends AbstractLocationProvider implements LocationListener {
  private static final String TAG = "LcmmLocationProvider";
  private static final int SIGNIFICANTLY_ACCURACY = 100;

  private static final int TEN_SECONDS = 1000 * 10;
  private static final int LEVEL_HIGH = 1;

  private static final float SNR_STRENGTH = 10;
  private LocationManager locationManager;
  private long mCheckPoint = 0L;

  private int findLocationAccount = 0;

  public LcmmLocationProvider(LocationService context) {
    super(context);
    PROVIDER_ID = 0;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    Log.i(TAG, "OnCreate");

    locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  }

  public void startRecording() {
    Log.i(TAG, "startRecording");

    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
      && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
      return;
    }
    lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    setLevel(LEVEL_HIGH);

  }

  public void stopRecording() {
    Log.d(TAG, "stopRecording");
    try {
      locationManager.removeGpsStatusListener(statusListener);
    } catch (Exception e1) {
      Log.e(TAG, "Something bad happened while removing status listener: " + e1.getMessage());
    }

    try {
      locationManager.removeUpdates(this);
    } catch (Exception e2) {
      Log.e(TAG, "Something bad happened while removing location updates: " + e2.getMessage());
    }

  }

  private void setLevel(int lv) {
    stopRecording();
    switch (lv) {

      case LEVEL_HIGH:
        try {
          if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, config.getInterval(), config.getDistanceFilter(), this);
          locationManager.addGpsStatusListener(statusListener);
        } catch (Exception e) {
          Log.e(TAG, "Something bad happened while request updates or add status listener: " + e.getMessage());
        }
        break;


    }
  }





  /** Checks whether two providers are the same */
  private boolean isSameProvider(String provider1, String provider2) {
    if (provider1 == null) {
      return provider2 == null;
    }
    return provider1.equals(provider2);
  }

  /** Determines whether one Location reading is better than the current Location fix
   * @param location  The new Location that you want to evaluate
   * @param currentBestLocation  The current Location fix, to which you want to compare the new one
   */
  private boolean isBetterLocation(Location location, Location currentBestLocation) {
    if (currentBestLocation == null) {
      // A new location is always better than no location
      return true;
    }

    // Check whether the new location fix is newer or older
    long timeDelta = location.getTime() - currentBestLocation.getTime();
    boolean isSignificantlyNewer = timeDelta > TEN_SECONDS;
    boolean isSignificantlyOlder = timeDelta < -TEN_SECONDS;
    boolean isNewer = timeDelta > 0;

    // If it's been more than two minutes since the current location, use the new location
    // because the user has likely moved
    if (isSignificantlyNewer) {
      return true;
      // If the new location is more than X minutes older, it must be worse
    } else if (isSignificantlyOlder) {
      return false;
    }

    // Check whether the new location fix is more or less accurate
    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
    boolean isLessAccurate = accuracyDelta > 0;
    boolean isMoreAccurate = accuracyDelta < 0;
    boolean isSignificantlyLessAccurate = accuracyDelta > SIGNIFICANTLY_ACCURACY;

    // Check if the old and new location are from the same provider
    boolean isFromSameProvider = isSameProvider(location.getProvider(),
      currentBestLocation.getProvider());

    // Determine location quality using a combination of timeliness and accuracy
    if (isMoreAccurate) {
      return true;
    } else if (isNewer && !isLessAccurate) {
      return true;
    } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
      return true;
    }
    return false;
  }





  public void onLocationChanged(Location location) {
    Log.d(TAG, "- onLocationChanged: " + location.getLatitude() + "," + location.getLongitude() + ", accuracy: " + location.getAccuracy() + ", speed: " + location.getSpeed());
    int n = ++findLocationAccount;
//
//        // Time delta
    long currentTime = System.currentTimeMillis();
    long duration = mCheckPoint == 0L ? mCheckPoint : currentTime - mCheckPoint;
    mCheckPoint = currentTime;

//      For debug
//        Toast.makeText(context, "mv:" + isMoving + ",acy:" + location.getAccuracy() + ",v:" + location.getSpeed() + ",p:" + location.getProvider() + ",df:" + n, Toast.LENGTH_SHORT).show();

    // Compare
    if (!isBetterLocation(location, lastLocation)) {
      return;
    }
    lastLocation = location;

    if (location.getSpeed() < config.getStationaryRadius()) {
      return;
    }

    //Push to service
    handleLocation(location);
  }

  private final GpsStatus.Listener statusListener = new GpsStatus.Listener() {

    @Override
    public void onGpsStatusChanged(int event) {
      switch (event) {
        case GpsStatus.GPS_EVENT_FIRST_FIX:
//					clu
//			    	Toast.makeText(context, "GPS first fix. ", Toast.LENGTH_SHORT).show();
          Log.w(TAG, "GPS first fix.");
          break;

        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
          if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          GpsStatus gpsStatus = locationManager.getGpsStatus(null);
          int maxSatellites = gpsStatus.getMaxSatellites();
					Iterator<GpsSatellite> iters = gpsStatus.getSatellites().iterator();
					int count = 0;
					while (iters.hasNext() && count <= maxSatellites) {
						GpsSatellite s =  iters.next();
						if (s.getSnr() > SNR_STRENGTH) {
							count++;
						}

						// Log.i(TAG, "GPS SNR is : " + s.getSnr());
					}
//					clu
//			    	Toast.makeText(context, "GPS count is: " + count, Toast.LENGTH_SHORT).show();
//			    	startTone("doodly_doo");
					handleGpsStatusChanged(count);
//          LogUtil.d(TAG, "GPS count is : " + count);
					break;

				case GpsStatus.GPS_EVENT_STARTED:
//					clu
//					Toast.makeText(context, "GPS started. ", Toast.LENGTH_SHORT).show();
					Log.w(TAG, "GPS started.");
					break;

				case GpsStatus.GPS_EVENT_STOPPED:
					Log.w(TAG, "GPS stopped.");
					break;
				default:
					Log.w(TAG, "GPS default.");
					break;
			}
		}
    };

    public void onProviderDisabled(String provider) {
        Log.d(TAG, "onProviderDisabled: " + provider);
    }

    public void onProviderEnabled(String provider) {
        Log.d(TAG, "onProviderEnabled: " + provider);
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        Log.d(TAG, "onStatusChanged: " + provider + ", status: " + status);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");

        stopRecording();
    }
}
